import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:http_parser/http_parser.dart';
import 'package:logger/logger.dart';
import 'package:lx_widgets_library/lx_widgets_library.dart';

/// HttpManager 是一个单例类，用于管理网络请求
class HttpManager {
  // 单例模式
  static final HttpManager _instance = HttpManager._internal();

  // dio实例
  late Dio _dio;

  // 日志记录器
  final Logger _logger = Logger();

  // 获取单例实例
  factory HttpManager() => _instance;

  // http状态码
  static const int _statusCode = 200; // 成功

  // 设置baseUrl
  String _baseUrl = 'https://api.example.com';
  set baseUrl(String url) {
    _baseUrl = url;
    _dio.options.baseUrl = url;
  }

  // 提供设置自定义拦截器的方法
  set dioInterceptor(DioInterceptor interceptor) {
    _dio.interceptors.clear(); // 清除默认拦截器
    _dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) async {
        await interceptor.onRequest(options, handler);
      },
      onResponse: (response, handler) async {
        // 检查是否为文件下载响应
        if (_isDownloadResponse(response)) {
          // 对于下载响应，直接传递给handler，不调用自定义拦截器
          handler.next(response);
        } else {
          // 对于普通JSON响应，调用自定义拦截器
          await interceptor.onResponse(response, handler);
        }
      },
      onError: (error, handler) async {
        _logger.e('请求错误: ${error.message}');
        await interceptor.onError(error, handler);
      },
    ));
    // 添加日志拦截器
    _addLoggerInterceptor();
  }

  // 私有构造函数
  HttpManager._internal() {
    // 初始化Dio
    _dio = Dio(
      BaseOptions(
        baseUrl: _baseUrl, // 基础URL
        connectTimeout: 10000, // 10秒连接超时
        receiveTimeout: 10000, // 10秒接收超时
        sendTimeout: 10000, // 10秒发送超时
        headers: {
          'Content-Type': 'application/json',
        },
      ),
    );
    // 添加日志拦截器
    _addLoggerInterceptor();
  }

  // 添加日志拦截器
  _addLoggerInterceptor() {
    _dio.interceptors.add(LogInterceptor(
      request: false,
      requestHeader: true,
      requestBody: true,
      responseHeader: true,
      responseBody: true,
      error: true,
    ));
  }

  // 请求
  Future<CustomResponse<T>> request<T extends BaseData>(
    RequestType requestType,
    String path,
    T Function(Map<String, dynamic>) fromJson, {
    Map<String, dynamic>? queryParameters,
    dynamic data,
    CancelToken? cancelToken,
    int retryTimes = 3,
  }) async {
    int attempt = 0;
    while (attempt < retryTimes) {
      try {
        final response = await _dio.request(
          path,
          queryParameters: queryParameters,
          data: data,
          options: Options(method: requestType.method),
          cancelToken: cancelToken,
        );
        return CustomResponse<T>.fromJson(response, fromJson);
      } on DioError catch (e) {
        // Extract status code from error response if available
        int? errorStatusCode = e.response?.statusCode;
        if (errorStatusCode != _statusCode) rethrow;
        attempt++;
        if (attempt >= retryTimes) rethrow;
        debugPrint('请求失败，正在重试... (尝试次数: $attempt/$retryTimes)');
        await Future.delayed(Duration(seconds: 1 * attempt));
      }
    }
    DioError e = DioError(requestOptions: RequestOptions(path: path));
    _handleError(e);
    throw e;
  }

  // 文件上传
  Future<CustomResponse<T>> uploadFile<T extends BaseData>(
    String path,
    String filePath,
    T Function(Map<String, dynamic>) fromJson, {
    String name = 'file',
    Map<String, dynamic>? data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    MediaType? contentType,
  }) async {
    String fileExtension =
        ImgUtils.getFileExtension(filePath).replaceAll(".", "");
    FormData formData = FormData.fromMap({
      ...?data,
      name: await MultipartFile.fromFile(
        filePath,
        contentType: contentType ??
            MediaType('image',
                fileExtension == "jpg" ? "jpeg" : fileExtension), // 根据实际文件类型设置
      ),
    });

    final response = await _dio.post(
      path,
      data: formData,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onSendProgress: onSendProgress,
    );
    return CustomResponse<T>.fromJson(response, fromJson);
  }

  // 文件下载
  Future<CustomResponse<T>> downloadFile<T extends BaseData>(
    String urlPath,
    String savePath,
    T Function(Map<String, dynamic>) fromJson, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
  }) async {
    final response = await _dio.download(
      urlPath,
      savePath,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onReceiveProgress: onReceiveProgress,
    );
    if (_isDownloadResponse(response)) {
      // 对于下载响应，直接返回一个成功的CustomResponse
      return CustomResponse<T>(
        originalResponse: response,
        code: 0,
        message: '',
      );
    }
    return CustomResponse<T>.fromJson(response, fromJson);
  }

  // 并发请求
  Future<List<Response>> concurrentRequests(List<Future<Response>> requests) {
    return Future.wait(requests);
  }

  // 错误处理
  void _handleError(DioError error) {
    switch (error.type) {
      case DioErrorType.connectTimeout:
        _logger.e('连接超时');
        break;
      case DioErrorType.sendTimeout:
        _logger.e('发送超时');
        break;
      case DioErrorType.receiveTimeout:
        _logger.e('接收超时');
        break;
      case DioErrorType.response:
        _logger.e('服务器响应错误: ${error.response?.statusCode}');
        break;
      case DioErrorType.cancel:
        _logger.e('请求被取消');
        break;
      case DioErrorType.other:
        _logger.e('网络错误: ${error.message}');
        break;
    }
  }

  // 判断是否为下载响应
  bool _isDownloadResponse(Response response) {
    return response.requestOptions.responseType == ResponseType.stream ||
        response.requestOptions.responseType == ResponseType.bytes ||
        response.data is ResponseBody;
  }

  // 取消请求
  void cancelRequests(CancelToken cancelToken) {
    cancelToken.cancel('请求被主动取消');
  }
}
